/**
 * Copyright (c) 2013 Mark Tielemans
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * DISCLAIMER
 * This software is provided "as is" and any expressed or implied warranties, including, but not limited to, the implied warranties of 
 * merchantability and fitness for a particular purpose are disclaimed. In no event shall the regents or contributors be liable for any 
 * direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute 
 * goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in 
 * contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if 
 * advised of the possibility of such damage.
 */
package nl.marktielemans.easydb.connection;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import nl.marktielemans.easydb.EasyDBConfig;

import org.apache.log4j.Logger;

/**
 * Connection manager for use with a MySQL database.
 * 
 * @author Mark Tielemans
 * @version	1.0
 * @since 1.0
 * @see DatabaseConnector
 */
public class MySQLConnector implements DatabaseConnector {
	
	private static final Logger logger = Logger.getLogger(MySQLConnector.class);
	public static final boolean AUTO_COMMIT = false;

	public MySQLConnector() {}

	/**
	 * Connects to the database and stores the connection locally.
	 * @return
	 */
	private Connection connect() {
		try {
			Class.forName("com.mysql.jdbc.Driver");
			logger.debug("jdbc driver registered");
		} catch (ClassNotFoundException e) {
			logger.error("Failed to register database driver", e);
			return null;
		}

		Connection conn;
		try {
			conn = DriverManager.getConnection("jdbc:mysql://"
					+EasyDBConfig.get().getDbHostUrl()
					+":"
					+EasyDBConfig.get().getDbHostPort()
					+"/"
					+ EasyDBConfig.get().getDbName(), EasyDBConfig.get().getDbUsername(), EasyDBConfig.get().getDbPassword());
		} catch (SQLException e) {
			logger.error("Database connection failed", e);
			return null;
		}
		
		if(conn == null) {
			logger.error("Failed to connect to database: unknown error");
			return null;
		}

		logger.debug("Connected to database");
		return conn;
	}

	@Override
	public Connection getConnection() throws SQLException {
		Connection conn = connect();
		if(conn == null) {
			logger.error("Connection to database failed.");
			throw new SQLException("Connection to database failed");
		}
		try {
			conn.setAutoCommit(AUTO_COMMIT);
		} catch (SQLException e) {
			logger.fatal("Failed to set auto commit settings, expect subsequent transaction failures");
		}
		return conn;
	}

	/**
	 * Execute an SQL statement on the server.
	 * @param statement
	 * @return true if the statement has succesfully executed.
	 * @throws SQLException
	 */
	@Override
	public void update(String statement) throws SQLException {
		Connection conn = getConnection();
		Statement stmt = null;
		try {
			stmt = conn.createStatement();
			logger.debug("Created statement");
			stmt.executeUpdate(statement);
			logger.debug("Executed update");
			conn.commit();
			logger.debug("Committed");
		} catch (SQLException e) {
			logger.error("SQL statement resulted in error", e);
			conn.rollback();
			throw e;
		} finally {
			if (stmt != null) { stmt.close(); }
		}
	}
	
	@Override
	public ResultSet query(String statement) throws SQLException {
		Connection conn = getConnection();
		Statement stmt = null;
		try {
			stmt = conn.createStatement();
			logger.debug("Created query statement");
			ResultSet result = stmt.executeQuery(statement);
			logger.debug("Executed query");
			conn.commit();
			logger.debug("Committed");
			return result;
		} catch (SQLException e) {
			logger.error("SQL statement resulted in error", e);
			conn.rollback();
			throw e;
		}
	}
}
